import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.api import users

from datetime import datetime
import logging
import string
import StringIO
import urllib

from pixeltoy import datelib
from pixeltoy import header
from pixeltoy import model
from pixeltoy import tracker


gallery_size = 30


gallery_template = string.Template('''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="files/site.css"/>
</head>
<body>
$header

<p>Visitors drew these pictures with <a href="/">PixelToy</a>.</p>
$next_link <a href="/">Return to PixelToy</a></p>
<div id="gallery">
$snapshots
</div>
<p style="clear: both">
$next_link <a href="/">Return to PixelToy</a></p>
<p><a href="http://feeds.feedburner.com/PixeltoyGallery" rel="alternate" type="application/rss+xml"
><img src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt=""
 style="vertical-align:middle;border:0"/></a>&nbsp;<a href="http://feeds.feedburner.com/PixeltoyGallery"
 rel="alternate" type="application/rss+xml">Subscribe in a reader</a></p>
<p><a href="/about">More about PixelToy</a></p>

$tracker
</body>
</html>
''')


next_link_template = string.Template('''
<a href="/gallery?before=${before_date}">Next Page</a> -
''')

snapshot_template = string.Template('''
<div class="snapshot">
<img src="/snapshot?id=${snapshot_id}" width="$width" height="$height">
$hide
</div>
''')

hide_button_template = string.Template('''
<form action="/hide" method="post">
<input type=hidden name="id" value="$snapshot_id"/>
<input type=hidden name="return_date" value="$current_page_date"/>
<input type=submit value='Hide'/>
</form>
''')

unhide_button_template = string.Template('''
<form action="/unhide" method="post">
<input type=hidden name="id" value="$snapshot_id"/><input type=submit value='Unhide'/>
</form>
''')


gallery_atom_template = string.Template('''<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>$host_url/-gallery-feed</id>
  <title>PixelToy Gallery</title>
  <author><name>Visitors to PixelToy</name></author>  
  <link rel="self" href="$host_url/feed"/>
  <link rel="alternate" href="$host_url/"/>
  <updated>$date_updated</updated>  
$snapshots
</feed>
''')


snapshot_atom_template = string.Template('''
<entry>
  <id>$host_url/-snapshot-${snapshot_id}</id>
  <title>PixelToy Snapshot</title>
  <updated>$date_created</updated>
  <content type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
    <img src="$host_url/snapshot?id=${snapshot_id}" width="$width" height="$height"
         xmlns="http://www.w3.org/1999/xhtml" />
    </div>
  </content>
</entry>
''')


def ShowGallery(want_hidden=False):
  return GalleryPage('text/html', gallery_template, snapshot_template, want_hidden)


def ShowGalleryAtom():
  return GalleryPage('text/xml', gallery_atom_template, snapshot_atom_template, want_hidden=False)


def ShowHidden():
  return ShowGallery(want_hidden=True)


class GalleryPage(webapp.RequestHandler):
  def __init__(self, content_type, gallery_template, snapshot_template, want_hidden):
    webapp.RequestHandler.__init__(self)
    self.content_type = content_type
    self.gallery_template = gallery_template
    self.snapshot_template = snapshot_template
    self.want_hidden = want_hidden

  def get(self):
    host=self.request.environ['SERVER_NAME']
    before_date = datetime.utcnow()
    if self.request.GET.has_key('before'):
      try:
        before_date = datelib.from_isodate(self.request.GET['before'])
      except datelib.ParseError:
        pass
    most_recent = model.Snapshot.all().order("-date_created").fetch(1)
    if len(most_recent) == 0:
      self.response.headers['Content-Type'] = "text/plain"
      self.response.out.write("No snapshots yet")      
      return
    date_updated = most_recent[0].date_created
    all_snapshots = \
      model.Snapshot.all().order("-date_created").filter("date_created <", before_date) \
      .filter("is_hidden =", self.want_hidden) \
      .fetch(gallery_size * 2)
    if self.want_hidden:
      wanted_snapshots_plus = [s for s in all_snapshots if s.hidden!=None]
    else:
      wanted_snapshots_plus = [s for s in all_snapshots if s.hidden==None]

    wanted_snapshots = wanted_snapshots_plus[:gallery_size]
    if len(wanted_snapshots) < len(wanted_snapshots_plus):
      next_link_date = wanted_snapshots[-1].date_created
    else:
      next_link_date = None
    self.response.headers['Content-Type'] = self.content_type
    self.response.out.write(self.make_page(host, wanted_snapshots, date_updated,
                                           before_date, next_link_date))

  def make_page(self, host, snapshots, date_updated, current_page_date, next_link_date):
    if next_link_date is None:
      next_link = ''
    else:
      before_date = urllib.quote(datelib.to_isodate(next_link_date))
      next_link = next_link_template.substitute(before_date=before_date)
    snapshots = self.make_snapshot_rows(snapshots, current_page_date)
    return self.gallery_template.substitute(date_updated=datelib.to_isodate(date_updated),
                                            snapshots=snapshots,
                                            tracker=tracker.make_tracker(host),
                                            host_and_port=self.request.host,
                                            host_url=self.request.host_url,
                                            header=header.make_header_html('/gallery'),
                                            next_link=next_link)

  def make_snapshot_rows(self, snapshots, current_page_date):
    logged_in = users.get_current_user()
    out = StringIO.StringIO()
    for snapshot in snapshots:
      snapshot_id = snapshot.key().id()
      if logged_in and snapshot.can_hide and not self.want_hidden:        
        hide = hide_button_template.substitute(snapshot_id=snapshot_id,
          current_page_date=datelib.to_isodate(current_page_date))
      elif self.want_hidden:
        hide = unhide_button_template.substitute(snapshot_id=snapshot_id)
      else:
        hide = ""
      out.write(self.snapshot_template.substitute(
          snapshot_id=snapshot_id,
          width=snapshot.width,
          height=snapshot.height,
          date_created=datelib.to_isodate(snapshot.date_created),
          host_and_port=self.request.host,
          host_url=self.request.host_url,
          hide=hide))
    return out.getvalue()


def show_error_page(response, message):
  response.headers['Content-Type'] = "text/plain"
  response.set_status(400)
  response.out.write(message)


class HideSnapshot(webapp.RequestHandler):
  def post(self):
    user = users.get_current_user()
    if not user:
      show_error_page(self.response, "Not logged in!")
      return

    id_string = self.request.get('id')
    if id_string is None:
      show_error_page(self.response, "No id!")
      return
    try:
      id = int(id_string)
    except ValueError:
      logging.warning("HideSnapshot got bad id string: %s", repr(id_string))
      show_error_page(self.response, "Bad id!")
      return

    return_date = datetime.utcnow()
    if self.request.POST.has_key('return_date'):
      try:
        return_date = datelib.from_isodate(self.request.POST['return_date'])
      except datelib.ParseError:
        pass

    def transaction(id):
      snapshot = model.Snapshot.get_by_id(ids=id)
      if snapshot is None or not snapshot.can_hide:
        return False
      action = model.SnapshotAction(parent=snapshot,
                                    action_type=db.Category('hide_snapshot'),
                                    done_by=user)
      action.put()
      snapshot.hidden = action
      snapshot.is_hidden = True
      snapshot.put()
      return True
    ok = db.run_in_transaction(transaction, id)
    if not ok:
      show_error_page(self.response, "Transaction failed!")
      return
    self.redirect("/gallery?before=" + urllib.quote(datelib.to_isodate(return_date)))


class UnhideSnapshot(webapp.RequestHandler):
  def post(self):
    user = users.get_current_user()
    if not user:
      return

    try:
      id = int(self.request.get('id'))
    except ValueError:
      return

    def transaction(id):
      snapshot = model.Snapshot.get_by_id(ids=id)
      if snapshot is None:
        return
      snapshot.hidden = None
      snapshot.can_hide = False
      snapshot.is_hidden = False
      snapshot.put()
    db.run_in_transaction(transaction, id)
    self.redirect("/hidden")


def main():
  application = webapp.WSGIApplication([('/gallery', ShowGallery),
                                        ('/feed', ShowGalleryAtom),
                                        ('/hide', HideSnapshot),
                                        ('/hidden', ShowHidden),
                                        ('/unhide', UnhideSnapshot)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == "__main__":
  main()
